#pragma once
#include <memory>

#include "Containers/Containers.h"
#include "Reflection/Function.h"



class CType;
class CGSharpClass;
class CScriptParameter;
class CByteCodeFile;
class CBreakpointSlot;
class CScriptFunction;

struct SScriptVariable
{
public:
    SScriptVariable()
    {

    }

    SScriptVariable(const CString & InName, CType* InType)
        :Name(InName)
        ,Type(InType)
    {

    }

    CString Name;
    CType* Type;
};


class CScriptFunctionBody : public IFunctor
{
public:
    CScriptFunctionBody(CScriptFunction* InOwner)
    {
        Owner=InOwner;
    }

    CAny Invoke(const TVector<CAny>& InArgs) override;

protected:
    CScriptFunction* Owner;
};



class CScriptFunction : public CFunction
{
public:
    CScriptFunction(CFunctionList* InParentList
        ,const CString & InFunctionName
        ,const SDecoratedType& InReturnType
        ,const TVector<SDecoratedType>& InParameters
        ,const TVector<CString>& InParameterNames
        ,TMap<EFunctionFlags, SReflectionMetaDataValue> InMetaData
        );


public:

    //@BreakpointSlots , every bytecode instruction  corresponding a breakpoint slot or  null
    //BreakpointSlots.Num()== instruction num
    void SetBody(std::shared_ptr<CByteCodeFile> InFile
        , uint64_t InStartIndex
        , uint64_t InEndIndex
        , const TVector<uint32_t> & InLinePositions
        , const TVector<SScriptVariable> & InVariables

        , const TVector<std::shared_ptr<CBreakpointSlot>>  & InBreakpointSlots 
        )
    {
        File=InFile;
        StartIndex=InStartIndex;
        EndIndex=InEndIndex;
        LinePositions=InLinePositions;
        Variables=InVariables;
        BreakpointSlots=InBreakpointSlots;

        Functor = std::make_unique<CScriptFunctionBody>(this);
    }

    const TVector<CString> & GetParameterNames() const
    {
        return ParameterNames;
    }

    std::shared_ptr<CByteCodeFile> GetFile() const
    {
        return File;
    }

    uint64_t GetStartIndex() const
    {
        return StartIndex;
    }

    uint64_t GetEndIndex() const
    {
        return EndIndex;
    }

    const TVector<uint32_t> & GetLinePositions() const
    {
        return LinePositions;
    }

    const TVector<SScriptVariable> & GetVariables() const
    {
        return Variables;
    }

    const TVector<std::shared_ptr<CBreakpointSlot>> & GetBreakpointSlots() const
    {
        return BreakpointSlots;
    }

    
protected:
    TVector<CString> ParameterNames;


    std::shared_ptr<CByteCodeFile> File;
    uint64_t StartIndex;
    uint64_t EndIndex;
    TVector<uint32_t>  LinePositions;
    TVector<SScriptVariable> Variables;
    TVector<std::shared_ptr<CBreakpointSlot>> BreakpointSlots;

    friend class CScriptFunctionBody;
};

